<?php
	/**
	 * @author Matthias Eigner | 0625203
	 */
    class Template extends Service implements IService {
        private $templates;
        private $baseReplaces;
        
		private $rawTemplateCache;
		private $rawDynamicCache;
				
        function __construct(){
            parent::__construct();
            $this->tmp_render = array();
            $this->tmp_file = array();
            $this->templates = array();
            $this->replace = array();
            $this->find = array();
			
			$this->rawTemplateCache = array();
			$this->rawDynamicCache = array();
			
            $this->loadConfig($GLOBALS['config']['root'].'_classes/Template/config.Template.php');

            $this->baseReplaces = array('root'=>$GLOBALS['tpl']['root'],
                                        'tpl_root_folder'=>'_template/'.$this->config['base_template'].'/'.$GLOBALS['Localization']['language'],
                                        'tpl_folder'=>'_template/'.$this->config['template'].'/'.$GLOBALS['Localization']['language'],
                                        'user_id'=>(isset($_SESSION['User'])) ? $_SESSION['User']['id'] : '',
                                        'user_nick'=>(isset($_SESSION['User'])) ? $_SESSION['User']['nick'] : '',
            							'aSID'=>(isset($_SESSION['ajax_sID'])) ?$_SESSION['ajax_sID']: '',
            							'msg_insert_success'=>$GLOBALS['Localization']['Db']['INSERT_SUCCESS'][$GLOBALS['Localization']['language']],
            							'msg_insert_error'=>$GLOBALS['Localization']['Db']['INSERT_ERROR'][$GLOBALS['Localization']['language']]);
            foreach($_GET as $key=>$get){
                if(!is_array($get)) $this->baseReplaces['GET:'.$key] = $get;
            }
            
            include($this->config['loc_file']);
            $GLOBALS['zindex'] = 100000;
        }
        /**
         *  args['tpl_url'] ...	template url, the first element is the templates name, every further string seperated with a slash is a sub template
         *  					e.g. news/news_item will load the dynamic "news_item" in the template "news". Note that the url has only two levels
         *  					max since Dynamic names have to be unique within the template.
         */
        public function view($args) {
            if(isset($args['tpl_url']) && $args['tpl_url'] != ''){
            	$parts = explode('/', $args['tpl_url']);
            	if(count($parts) == 1){
            		return $this->renderTemplate($parts[0], $args, array());
            	} else {
            		return $this->renderDynamic($parts[0], $parts[1], $args, array());
            	}
            }
        	return '';
        }
        public function admin($args){
            return '';
        }
        public function run($args){
            return false;
        }
        public function data($args){
            return '';
        }
        

		
		/**
		 *	Renders the specified template and returns the result
		 *	
		 *	@param $tID The name of the template file
		 *	@param $values An array of replace values with the corresponding single value placeholder name as key
		 *  @param $blocks An array of replace values with the corresponding block placeholder name as key
		 *
		 *	@return string
		 */
		function renderTemplate($tID, $values, $blocks){
		    /*$GLOBALS['extra_css'] = array_unique($GLOBALS['extra_css']);
			//get the template
			$this->baseReplaces['extra_css'] = $this->renderCss($GLOBALS['extra_css']);
            $this->baseReplaces['extra_js'] = $this->renderJs($GLOBALS['extra_js']);
             */
			$tpl = $this->getRawTemplate($tID);
			
			//do the parsing
			$tpl = $this->replaceValues($tpl, $values);
			$tpl = $this->replaceDynamics($tpl, $blocks);
			$tpl = $this->parseServiceTags($tpl);
			
			return $tpl;
		}
		
        private function renderCss($array) {
            $return = '';
            foreach($array as $row) {
                $return .= '<link rel="stylesheet" type="text/css" href="'.$GLOBALS['tpl']['root'].'_template/'.$this->config['template'].'/'.$GLOBALS['Localization']['language'].'/css/'.$row.'" />'."\n";
            }
            return $return;
        }
        
        private function renderJs($array) {
            $return = '';
            foreach($array as $row) {
                $return .= '<script type="text/javascript" src="'.$GLOBALS['tpl']['root'].'_template/'.$this->config['template'].'/'.$GLOBALS['Localization']['language'].'/js/'.$row.'"></script>'."\n";
            }
            return $return;
        }
		
		/**
		 *	Renders the specified dynamic in the specified template and returns the result
		 *	
		 *	@param $tID The name of the template file
		 *	@param $dID The name of the dynamic block in the template
		 *	@param $values An array of replace values with the corresponding single value placeholder name as key
		 *  @param $blocks An array of replace values with the corresponding block placeholder name as key
		 *
		 *	@return string
		 */
		function renderDynamic($tID, $dID, $values, $blocks){
			if(isset($this->rawDynamicCache[$tID][$dID])){
				$dyn = $this->rawDynamicCache[$tID][$dID];
			} else {
				//get the template
				$tpl = $this->getRawTemplate($tID);
			
				//find the start and end tag
				$posStart = strpos($tpl, '<pp:dynamic name="'.$dID.'">') + strlen('<pp:dynamic name="'.$dID.'">');
				$nextStart = strpos($tpl, '<pp:dynamic', $posStart);
				$posEnd = strpos($tpl, '</pp:dynamic>', $posStart);
				
				while($nextStart !== false && $nextStart < $posEnd){
					$posEnd = strpos($tpl, '</pp:dynamic>', $posEnd+13);
					$nextStart = strpos($tpl, '<pp:dynamic', $nextStart+20);
				}
				
				if($posStart < $posEnd){
				
					//cut dynamic block from template
					$dyn = substr($tpl, $posStart, $posEnd-$posStart);
					
					//cache unparsed dynamic
					if(!isset($this->rawDynamicCache[$tID])) $this->rawDynamicCache[$tID] = array();
					$this->rawDynamicCache[$tID][$dID] = $dyn;
					
				} else {
					$GLOBALS['Messages'][] = '<span class="msg_error">'.str_replace(array('[%dynamic%]', '[%template%]'), array($dID, $tID), $this->_('DYNAMIC_NOT_FOUND')).'</span>';
					return false;
				}
			}
			
			if($dyn != ''){
				//do the parsing
				$dyn = $this->replaceValues($dyn, $values);
				$dyn = $this->replaceDynamics($dyn, $blocks);
				$dyn = $this->parseServiceTags($dyn);
			}
			
			return $dyn;
		}
		
		/**
		 *	Returns the unparsed template to the given name
		 *	
		 *	@param $tID The name of the template
		 *
		 *	@return string
		 */
		private function getRawTemplate($tID){
			$tpl = '';
			if(isset($this->rawTemplateCache[$tID])){
				$tpl = $this->rawTemplateCache[$tID];
			} else {
				//TODO load file
				$file = $GLOBALS['config']['root'].'_template/'.$this->config['template'].'/'.$GLOBALS['Localization']['language'].'/'.$tID.'.html';
				if(!is_file($file)) $file = $GLOBALS['config']['root'].'_template/'.$this->config['base_template'].'/'.$GLOBALS['Localization']['language'].'/'.$tID.'.html';
				if(is_file($file)){
					$tpl = $this->loadFile($file);
					$this->rawTemplateCache[$tID] = $tpl;
				} else {
					//$this->sp->msg->data(array('message'=>str_replace(array('[%datei%]'), array($file),$this->_('FILE_NOT_FOUND')), 'type'=>Messages::ERROR));
					return str_replace(array('[%datei%]'), array($file),$this->_('FILE_NOT_FOUND'));
				}
			}
			return $tpl;
		}
		
		/**
		 *	Replaces the dynamic placeholders within the given template.
		 *	e.g. <pp:dynamic name="myDyn"> ... </pp:dynamic> will be replaced with $block['myDyn']
		 *
		 *	@param $tpl The unparsed template
		 *	@param $blocks An array of replace values with the corresponding block placeholder name as key
		 *
		 *	@return string
		 */
		private function replaceDynamics($tpl, $blocks){
			//find and replace dynamic blocks
			foreach ($blocks as $key => $value) {
				
				$posStart = strpos($tpl, '<pp:dynamic name="'.$key.'">');
				$nextStart = strpos($tpl, '<pp:dynamic', $posStart + 20);
				$posEnd = strpos($tpl, '</pp:dynamic>', $posStart) + strlen('</pp:dynamic>');

				while($nextStart !== false && $nextStart < $posEnd){
					$posEnd = strpos($tpl, '</pp:dynamic>', $posEnd) + strlen('</pp:dynamic>');
					$nextStart = strpos($tpl, '<pp:dynamic', $nextStart+20);
				}
				
				$tpl = substr_replace($tpl, $value, $posStart, $posEnd - $posStart);
			}
			
			return $tpl;
		}
		
		/**
		 *	Replaces the single value placeholders within the given template.
		 *	e.g. {@pp:myValue} will be replaced with $value['myValue']
		 *
		 *	@param $tpl The unparsed template
		 *	@param $values An array of replace values with the corresponding single value placeholder name as key
		 *
		 *	@return string
		 */
		private function replaceValues($tpl, $values){			
			//find first tag
			$firstPos = strpos($tpl, '{@');
			if($firstPos !== false){
				//if there is a tag go on with replacing
				$front = substr($tpl, 0, $firstPos); 
				$tpl = substr($tpl, $firstPos+2); 			
				
				//merge values with standard values
				$values = array_merge($values, $this->baseReplaces);
				
				//split the template into chunks
				$tplChunks = explode('{@', $tpl);
				
				//split all the chunks again
				foreach($tplChunks as &$chunk){
					$parts = explode('}', $chunk, 2);
					$name = explode(':', $parts[0], 2);
					//check if really single value
					if(preg_match('/[^a-zA-Z0-9_]+/', $name[1]) < 1){
						if($name[0] == 'pp') $chunk = @$values[$name[1]].@$parts[1];
						else if($name[0] == 'get' || $name[0] == 'GET') $chunk = @$_GET[$name[1]].@$parts[1];
						else if($name[0] == 'post' || $name[0] == 'POST') $chunk = @$_POST[$name[1]].@$parts[1];
						else if($name[0] == 'server' || $name[0] == 'SERVER') $chunk = @$_SERVER[$name[1]].@$parts[1];
						else if($name[0] == 'cookie' || $name[0] == 'COOKIE') $chunk = @$_COOKIE[$name[1]].@$parts[1];
					} else {
						$chunk = '{@pp:'.$chunk;
					}
				}
				unset($chunk);
				
				return $front.implode($tplChunks);
			} else {
				return $tpl;
			}
		}
		
		/**
		 *	Parses all service tags in a template and replaces them with the results.
		 *	A service tag would look like the following
		 *	{pp:myService(arg1:value, arg2:value2, arg3:value3)}
		 *	
		 *	@param $tpl the unparsed template
		 *
		 *	@return string
		 */
		private function parseServiceTags($tpl){
			//split the template into chunks
			$firstPos = strpos($tpl,'{pp:');
			$tplChunks = explode('{pp:', $tpl);
			
			//split all the chunks again
			foreach($tplChunks as &$chunk){
				if($firstPos === 0){
					$parts = explode(')}', $chunk, 2);
					if(count($parts) == 2){
						$pos = strpos($parts[0], '(');
						//get the arguments
						$argChunks = explode(',', substr($parts[0],$pos+1));
						//parse the arguments
						$args = array();
						foreach($argChunks as &$arg){
							$argPair = explode(':', $arg);
							if(count($argPair) == 2){
								$args[trim($argPair[0])] = trim($argPair[1]);
							}
						}
						unset($arg);
						//get the service result 
						$result = $this->sp->view(substr($parts[0], 0, $pos), $args);
						$chunk = $result.$parts[1];
					}
				} else {
					$firstPos = 0;
				}
			}
			unset($chunk);
			
			return implode($tplChunks);
		}
		
        private function addTemplate($id){
            if(!in_array($id, array_keys($this->templates))){
                $this->templates[$id] = array();
                return true;
            } else return false;
        }
        
        public static function generateMenu($tpl, $selected, $count=10){
        	for($i=0;$i<$count;$i++){
        		$class = ($i==$selected) ? 'class="active"': '';
        		$img = ($i==$selected) ? '_active': '';
        		$tpl->addValue('menu_'.$i, $class);
        		$tpl->addValue('menu_img_'.$i, $img);
        	}
        }
        public static function addBreadCrumb($link, $text){
        	$GLOBALS['breadcrumb'][] = array('link'=>$link, 'text'=>$text, 'z_index'=>$GLOBALS['zindex']--);
        }
        public static function renderBreadCrumb($tpl){
        	if(isset($GLOBALS['breadcrumb'])){
        		foreach($GLOBALS['breadcrumb'] as $bc){
        			$tmp = new SubViewDescriptor('breadcrumb');
        			$tmp->addValue('link', $bc['link']);
        			$tmp->addValue('text', $bc['text']);
        			$tmp->addValue('z_index', $bc['z_index']);
        			
        			$tpl->addSubView($tmp);
        			unset($tmp);
        		}
        	}
        }
        
        public static function cutString($string, $count){
        	if(strlen($string) <= $count){
        		return $string;
        	} else {
        		if($count > 3){
        			return substr($string, 0, $count-3).'...';
        		} else return '...';
        	}
        }
        
        public static function getPagina($page, $pp, $allpages, $url){
        	$return = new ViewDescriptor('content/parts/pagina');
        	$pages = ceil($allpages/$pp);
        	for($i=$pages;$i>0;$i--){
        		$p = new SubViewDescriptor('page');
        		$act = ($page == $i) ? 'class="active"' : '';
        		$p->addValue('active', $act);
        		$p->addValue('id', $i);
        		$p->addValue('url', str_replace('{@pp:page}', $i, $url));
        		
        		$return->addSubView($p);
        		unset($p);
        	}
        	if($pages == 0){
        		$return->removeSubView('page');
        	}
        	return $return->render();
        }
        
    }
?>